package com.rags.chess.move;

import com.rags.chess.base.Color;
import com.rags.chess.base.Coordinate;
import com.rags.chess.base.Piece;
import com.rags.chess.game.Game;
import com.rags.chess.game.GameHelper;

public abstract class Move implements Cloneable {
	private String notation;
	private Game game;
	private Coordinate start;
	private Coordinate end;
	private Object moveCallbackListener;

	protected Move() {}
	
	public Move(Game aGame, Coordinate aStart, Coordinate anEnd, Object aMoveCallBackListener) {
		game = aGame;
		start = aStart;
		end = anEnd;
		moveCallbackListener = aMoveCallBackListener;
		Piece piece = game.getPiece(start); 
		if (piece == null)
			throw new IllegalArgumentException(String.format("No piece found on %s", start));
		if (!piece.getColor().equals(aGame.getMoveTurn()))
			throw new IllegalArgumentException(String.format("Out of turn move: %s", piece.getColor()));

		notation = String.format("%s%s", deriveNotation(game, start, end), checkNotation());
		
		if (isInCheck(game, start, end))
			throw new IllegalMoveException("You are in check!");
	}
	
	protected String checkNotation() {
		Game newGame = new Game(game);
		makeMove(newGame, start, end);
		Color newGameMoveTurn = newGame.getMoveTurn() == Color.WHITE? Color.BLACK : Color.WHITE;
		newGame.setMoveTurn(newGameMoveTurn);
		if (GameHelper.isInCheckmate(newGame, newGameMoveTurn))
			return "#";
		if (GameHelper.isInCheck(newGame, newGameMoveTurn))
			return "+";
		return "";
	}

	protected boolean isInCheck(Game g, Coordinate begin, Coordinate finish) {
		Game newGame = new Game(g);
		makeMove(newGame, begin, finish);
		return GameHelper.isInCheck(newGame, newGame.getMoveTurn());
	}

	public void makeMove() {
		makeMove(game, start, end);
	}

	public String getNotation() {
		return notation;
	}
	
	public void setNotation(String aNotation) {
		this.notation = aNotation;
	}

	public Object getMoveCallbackListener() {
		return moveCallbackListener;
	}

	protected abstract String deriveNotation(Game game, Coordinate start, Coordinate end);
	protected abstract void makeMove(Game game, Coordinate start, Coordinate end);

	public Coordinate getStart() {
		return start;
	}

	public Coordinate getEnd() {
		return end;
	}

	public void setGame(Game game) {
		this.game = game;
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
